﻿using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace Lean.NantTasks.Deployment
{
    internal class RemoteCredentials
    {
        // logon types
        private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

        // logon providers
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
                                             int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool CloseHandle(IntPtr handle);


        public static void DoAs(string username, string domain, string password, Action doWork)
        {
            IntPtr token = IntPtr.Zero;
            bool isSuccess = LogonUser(username, domain, password,
                                       LOGON32_LOGON_NEW_CREDENTIALS,
                                       LOGON32_PROVIDER_DEFAULT, ref token);
            if (!isSuccess) {
                RaiseLastError();
            }
            
            var newIdentity = new WindowsIdentity(token);
            using (newIdentity.Impersonate())
            {
                doWork();
            }

            isSuccess = CloseHandle(token);
            if (!isSuccess) {
                RaiseLastError();
            }
        }

        private static void RaiseLastError()
        {
            int errorCode = Marshal.GetLastWin32Error();
           // string errorMessage = GetErrorMessage( errorCode );

            throw new ApplicationException( errorCode.ToString() );
        }
    }
}